﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using FastCodeGeneration.Core.Constant;
using FastCodeGeneration.Core.Utility;
using Newtonsoft.Json.Linq;
using SqlSugar;
using SqlSugar.IOC;

namespace FastCodeGeneration.Core.Framework
{
    public abstract class BaseRepository<T> : SimpleClient<T>, IBaseRepository<T> where T : class, new()
    {
        protected readonly SqlSugarScope dataBase;

        protected Dictionary<string, string> _fieldsAndColumnDictionary;

        protected string tableName;

        /// <summary>
        /// 通过字段名获取表列名
        /// </summary>
        /// <param name="fieldName">字段名</param>
        /// <returns>表列名</returns>
        public string getTableColumnByFieldName(string fieldName)
        {
            if (!_fieldsAndColumnDictionary.ContainsKey(fieldName.ToLower()))
            {
                return string.Empty;
            }
            return _fieldsAndColumnDictionary[fieldName.ToLower()];
        }

        protected BaseRepository()
        {
            dataBase = DbScoped.SugarScope;
            Context = dataBase;
            if (_fieldsAndColumnDictionary == null)
            {
                _fieldsAndColumnDictionary = new Dictionary<string, string>();
            }

            var type = typeof(T);
            tableName = type.Name.ToCamelToUnderline();
            var properties = type.GetProperties();
            var sugarTable = type.GetCustomAttribute<SugarTable>();
            if (sugarTable != null)
            {
                tableName = sugarTable.TableName;
            }

            foreach (var property in properties)
            {
                var sugarColumnAttribute = property.GetCustomAttribute<SugarColumn>();
                if (sugarColumnAttribute != null && !sugarColumnAttribute.IsIgnore)
                {
                    _fieldsAndColumnDictionary.Add(property.Name.ToLower(), sugarColumnAttribute.ColumnName);
                }
                else if (sugarColumnAttribute == null)
                {
                    _fieldsAndColumnDictionary.Add(property.Name.ToLower(), property.Name.ToCamelToUnderline());
                }
            }

        }
        private void setConditionToWrapper(string[] array, QueryWrapper<T> queryWrapper)
        {
            int connectorNumber = (array.Length - 3) / 4;
            for (int j = 0; j < connectorNumber + 1; j++)
            {
                //从数组中拆分出where条件
                string[] conditionArr = array.Skip(j * 4).Take(3).ToArray();
                //设置where条件到QueryWrapper中
                if (conditionArr[1].ToString().ToLower() == AppConstant.EQ.ToLower())
                {
                    queryWrapper.Eq(this.getTableColumnByFieldName(conditionArr[0].ToString()), conditionArr[2]);
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.NE.ToLower())
                {
                    queryWrapper.Ne(this.getTableColumnByFieldName(conditionArr[0].ToString()), conditionArr[2]);
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.GT.ToLower())
                {
                    queryWrapper.Gt(this.getTableColumnByFieldName(conditionArr[0].ToString()), conditionArr[2]);
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.GE.ToLower())
                {
                    queryWrapper.Ge(this.getTableColumnByFieldName(conditionArr[0].ToString()), conditionArr[2]);
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.LT.ToLower())
                {
                    queryWrapper.Lt(this.getTableColumnByFieldName(conditionArr[0].ToString()), conditionArr[2]);
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.LE.ToLower())
                {
                    queryWrapper.Le(this.getTableColumnByFieldName(conditionArr[0].ToString()), conditionArr[2]);
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.IN.ToLower())
                {
                    string[] strings = conditionArr[2].ToString().Split(AppConstant.COMMA);
                    queryWrapper.In(this.getTableColumnByFieldName(conditionArr[0].ToString()), (Object[])strings);
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.NOT_IN.ToLower())
                {
                    string[] strings = conditionArr[2].ToString().Split(AppConstant.COMMA);
                    queryWrapper.NotIn(this.getTableColumnByFieldName(conditionArr[0].ToString()), (Object[])strings);
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.LIKE.ToLower())
                {
                    queryWrapper.Like(this.getTableColumnByFieldName(conditionArr[0].ToString()), conditionArr[2].ToString());
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.NONE.ToLower())
                {
                    //queryWrapper.isNull(this.getTableColumnByFieldName(conditionArr[0].toString()));
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.NOT_NONE.ToLower())
                {
                    //queryWrapper.isNotNull(this.getTableColumnByFieldName(conditionArr[0].toString()));
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.BETWEEN.ToLower())
                {
                    //String[] strings = conditionArr[2].toString().split(AppConstant.COMMA);
                    //queryWrapper.between(this.getTableColumnByFieldName(conditionArr[0].toString()), strings[0], strings[1]);
                }
                if (conditionArr[1].ToString().ToLower() == AppConstant.NOT_BETWEEN.ToLower())
                {
                    //String[] strings = conditionArr[2].toString().split(AppConstant.COMMA);
                    //queryWrapper.notBetween(this.getTableColumnByFieldName(conditionArr[0].toString()), strings[0], strings[1]);
                }

                //获取条件连接符(and || or)在数组中的index
                int connectorIndex = 3 + (j * 4);
                //如果条件连接符是or需要改为or来连接
                if (connectorIndex < array.Length && array[connectorIndex].ToString().ToLower() == AppConstant.OR.ToLower())
                {
                    queryWrapper.or();
                }
            }
        }

        public QueryWrapper<T> getQueryWrapperByCondition(Condition condition)
        {
            QueryWrapper<T> wrapper = new QueryWrapper<T>();
            //一、设置where查询条件
            if (condition.Filter.IsNotBlank())
            {
                var objects = JsonUtility.GetArray(condition.Filter);
                String connector = AppConstant.AND;

                if (objects != null)
                {
                    for (int i = 0; i < objects.Length; i++)
                    {
                        //1. 如果是数组
                        if (objects[i].StartsWith(AppConstant.LEFT_MIDDLE_BRACKET)
                                && objects[i].EndsWith(AppConstant.RIGHT_MIDDLE_BRACKET))
                        {
                            //获取数组中封装的where参数和值 example : ["name","=","1","or","age","=","2","and","gender","=","man"]
                            var array = JsonUtility.GetArray(objects[i].ToString());
                            if (connector == AppConstant.AND)
                            {
                                wrapper.and(queryWrapper => this.setConditionToWrapper(array, queryWrapper));
                            }
                            else
                            {
                                wrapper.or(queryWrapper => setConditionToWrapper(array, queryWrapper));
                            }
                        }
                        else if (objects[i].ToLower() == AppConstant.AND)
                        {
                            //2. 如果是条件连接符(and)
                            connector = AppConstant.AND;
                        }
                        else if (objects[i].ToLower() == AppConstant.OR)
                        {
                            //2. 如果是条件连接符(or)
                            connector = AppConstant.OR;
                        }
                    }
                }
            }

            //二、设置排序字段
            if (condition.Sort.IsNotBlank())
            {
                var sortArr = JsonUtility.GetArray(condition.Sort);
                if (sortArr != null)
                {
                    foreach (string sortItem in sortArr)
                    {
                        if (sortItem.IsNotBlank())
                        {
                            string[] sortParams = sortItem.Split(AppConstant.COMMA);
                            if (sortParams[1] == AppConstant.ASC)
                            {
                                //wrapper.orderByAsc(this.getTableColumnByFieldName(sortParams[0]));
                            }
                            else
                            {
                                //wrapper.orderByDesc(this.getTableColumnByFieldName(sortParams[0]));
                            }
                        }
                    }
                }
            }

            //三、设置查询字段
            //if (StringUtils.isNotBlank(condition.getFields()))
            //{
            //    if (condition.isExcludeFields())
            //    {
            //        JSONArray fields = JSON.parseArray(condition.getFields());
            //        List<String> tableColumns = this.getFieldsAndTableColumnMap().keySet().stream()
            //                .filter(e-> !fields.contains(e)).map(this::getTableColumnByFieldName).collect(Collectors.toList());
            //        wrapper.select(tableColumns);
            //    }
            //    else
            //    {
            //        JSONArray fields = JSON.parseArray(condition.getFields());
            //        List<String> tableColumns = new ArrayList<>();
            //        for (Object field : fields)
            //        {
            //            tableColumns.add(this.getTableColumnByFieldName(field.toString()));
            //        }
            //        wrapper.select(tableColumns);
            //    }
            //}
            return wrapper;
        }

        #region 查询方法

        /// <summary>
        /// 根据主值查询单条数据
        /// </summary>
        /// <param name="id">主键值</param>
        /// <returns>泛型实体</returns>
        public T SelectById(dynamic id)
        {
            return Context.Queryable<T>().InSingle(id);
        }

        /// <summary>
        /// 根据id集合查询
        /// </summary>
        /// <param name="ids">主键值</param>
        /// <returns>泛型实体</returns>
        public List<T> SelectByIds(IEnumerable<dynamic> ids)
        {
            return Context.Queryable<T>().In(ids).ToList();
        }

        /// <summary>
        /// 查询全部数据
        /// </summary>
        /// <returns></returns>
        public List<T> SelectAll()
        {
            return Context.Queryable<T>().ToList();
        }

        /// <summary>
        /// 查询count
        /// </summary>
        /// <param name="predicate">条件</param>
        /// <returns></returns>
        public long SelectCount(Expression<Func<T, bool>> predicate)
        {
            return Context.Queryable<T>().Count(predicate);
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="predicate">条件</param>
        /// <returns></returns>
        public T SelectOne(Expression<Func<T, bool>> predicate)
        {
            return GetFirst(predicate);
        }

        /// <summary>
        /// 查询集合
        /// </summary>
        /// <param name="predicate">条件</param>
        /// <returns></returns>
        public List<T> SelectList(Expression<Func<T, bool>> predicate)
        {
            return Context.Queryable<T>().WhereIF(predicate != null, predicate).ToList();
        }


        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="page">分页封装</param>
        /// <param name="wrapper">查询条件</param>
        /// <returns></returns>
        public IPage<T> SelectPage(IPage<T> page, QueryWrapper<T> wrapper)
        {
            int totalNumber = 0;
            if (wrapper != null && wrapper.GetSugarParameters().Count > 0)
            {
                var sql = $"SELECT * FROM {tableName} WHERE {wrapper.getSqlResult()}";
                page.Records = Context.SqlQueryable<T>(sql).AddParameters(wrapper.GetSugarParameters()).ToPageList(page.PageIndex, page.PageSize, ref totalNumber);
            }
            else
            {
                page.Records = Context.Queryable<T>().ToPageList(page.PageIndex, page.PageSize, ref totalNumber);
            }
            page.TotalCount = totalNumber;
            return page;
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="">前端条件封装</param>
        /// <returns></returns>
        public IPage<T> SelectPage(Condition condition)
        {
            QueryWrapper<T> wrapper = this.getQueryWrapperByCondition(condition);
            if (condition.ExportAll)
            {
                condition.PageSize = 10000;
            }
            Page<T> page = new Page<T>(condition.PageIndex, condition.PageSize);
            int totalNumber = 0;
            if (wrapper.GetSugarParameters().Count > 0)
            {
                var sql = $"SELECT * FROM {tableName} WHERE {wrapper.getSqlResult()}";
                page.Records = Context.SqlQueryable<T>(sql).AddParameters(wrapper.GetSugarParameters())
                    .ToPageList(page.PageIndex, page.PageSize, ref totalNumber);
            }
            else
            {
                page.Records = Context.Queryable<T>().ToPageList(page.PageIndex, page.PageSize, ref totalNumber);
            }
            page.TotalCount = totalNumber;
            return page;
        }
        #endregion


        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity">对象</param>
        /// <returns></returns>
        public T InsertEntity(T entity)
        {
            return this.InsertReturnEntity(entity);
        }


        /// <summary>
        /// 批量添加
        /// </summary>
        /// <param name="entities">对象集合</param>
        public bool BatchInsert(List<T> entities)
        {
            return Context.Insertable(entities).ExecuteCommand() > 0;
        }


        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity">对象</param>
        /// <returns></returns>
        public bool UpdateEntity(T entity)
        {
            return Context.Updateable(entity).ExecuteCommand() > 0;
        }

        /// <summary>
        /// 批量更新
        /// </summary>
        /// <param name="entities">对象集合</param>
        /// <returns>行数</returns>
        public bool BatchUpdate(List<T> entities)
        {
            return Context.Updateable(entities).ExecuteCommand() > 0;
        }

        /// <summary>
        /// 添加或更新
        /// </summary>
        /// <param name="entity">对象</param>
        /// <returns>行数</returns>
        public bool Save(T entity)
        {
            return Context.Storageable(entity).ExecuteCommand() > 0;
        }

        /// <summary>
        /// 添加或更新
        /// </summary>
        /// <param name="entities">对象集合</param>
        /// <returns>行数</returns>
        public bool BatchSave(List<T> entities)
        {
            return Context.Storageable(entities).ExecuteCommand() > 0;
        }

        /// <summary>
        ///     执行sql语句并返回List<T>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public List<T> SqlQuery(string sql, List<SugarParameter> parameters)
        {
            var list = Context.Ado.SqlQuery<T>(sql, parameters);
            return list;
        }
    }
}
